//
//  ControlFlow.swift
//  cnswift-demo
//
//  Created by YangWei on 2020/12/23.
//  Copyright © 2020 YangWei. All rights reserved.
//

import UIKit

class ControlFlow: SWDBaseObject {
    
    class func run() {
        
        let controlFlow = ControlFlow()
        
        // 1.0
        controlFlow.forInLoops()
        
        // 2.1
        controlFlow.whileLoops()
        
        // 2.2
        controlFlow.repeatWhile()
        
        // 3.1
        controlFlow.usingIf()
        
        // 3.2.0
        controlFlow.usingSwitch()
        
        // 3.2.1
        controlFlow.noImplicitFallthrough()
        
        // 3.2.2
        controlFlow.intervalMatching()
        
        // 3.2.3
        controlFlow.tuples()
        
        // 3.2.4
        controlFlow.valueBindings()
        
        // 3.2.5
        controlFlow.usingWhere()
        
        // 3.2.6
        controlFlow.compoundCases()
        
        // 4.1
        controlFlow.usingContinue()
        
        // 4.2.2
        controlFlow.breakInASwitchStatement()
        
        // 4.3
        controlFlow.usingFallthrough()
        
        // 4.4
        controlFlow.labeledStatements()
        
        // 5
        controlFlow.earlyExit()
        
        // 6
        controlFlow.checkingAPIAvailability()
    }
    
    /// 1.0 For-in 循环
    func forInLoops() {
       
        let title = "1.0 For-in 循环";
        printStartLine(title)
        
        /* 遍历数组 */
        let names = ["Anna", "Alex", "Brian", "Jack"]
        for name in names {
            print("Hello, \(name)!")
        }
        
        /* 遍历字典 */
        let numberOfLegs = ["spider": 8, "ant": 6, "cat": 4]
        for (animalName, legCount) in numberOfLegs {
            print("\(animalName)s have \(legCount) legs")
        }
        
        /* 遍历数字区间 */
        for index in 1...5 {
            print("\(index) times 5 is \(index * 5)")
        }
        
        /* 用不着数字区间的 index，可以使用下划线来取代遍历名以忽略 */
        let base = 3
        let power = 10
        var answer = 1
        // 10个3相乘(3的10次方)
        for _ in 1...power {
            answer *= base
        }
        print("\(base) to the power of \(power) is \(answer)")
        
        /* 遍历半开区间 */
        let minutes = 60
        // 从0～59（一分钟60秒间隔）
        print("0~59")
        for tickMark in 0..<minutes {
            // render the tick mark each minute (60 times)
            print(tickMark)
        }
        
        /* 使用 stride(from:to:by:) 函数来跳过不想要的标记 */
        let minuteInterval = 5
        // 每5秒间隔一次
        print("(0, 5, 10, 15 ... 45, 50, 55)")
        for tickMark in stride(from: 0, to: minutes, by: minuteInterval) {
            // render the tick mark every 5 minutes (0, 5, 10, 15 ... 45, 50, 55)
            print(tickMark)
        }
        
        printEndLine(title)
    }
    
    /// 2.1 While
    func whileLoops() {
       
        let title = "2.1 While";
        printStartLine(title)
        
        /* 玩蛇与梯子（也叫滑梯与梯子）
         游戏规则
         - 棋盘拥有 25 个方格，目标就是到达或者超过第 25 号方格；
         - 每一次，扔一个六面色子，安装方格的数字移动，依据水平的线路，如图安装上边虚线箭头标注的路线；
         - 如果停留在了梯子的下边，就可以顺着梯子爬上去；
         - 如果停留在了蛇的头上，就要顺着蛇滑下来
         */
        
        // 1）棋格数值初始化 棋盘使用 26 个零 Int 值初始化，而不是 25 个（从 0  到 25 ）
        let finalSquare = 25
        var board = [Int](repeating: 0, count: finalSquare + 1)
        
        // 2）根据方格内容，设置不同的值
        // - 有梯子的方格设置一个正数来移动到棋盘的上方，继续前进
        // - 有蛇的方格设置一个负数来让从棋盘上倒退
        
        board[03] = +08 // 梯子，前进 8
        board[06] = +11 // 梯子，前进 11
        board[09] = +09 // 梯子，前进 9
        board[10] = +02 // 梯子，前进 2
        board[14] = -10 // 蛇，退 10
        board[19] = -11 // 蛇，退 11
        board[22] = -02 // 蛇，退 2
        board[24] = -08 // 蛇，退 8
        
        // 3）开始扔色子
        var square = 0
        var diceRoll = 0
        while square < finalSquare {
            // 扔色子不是使用随机数，而是以 while 循环，每次加（1，2，3，4，5，6，1......）
            diceRoll += 1
            if diceRoll == 7 {
                diceRoll = 1
            }
            // move by the rolled amount
            square += diceRoll
            if square < board.count {
                // if we're still on the board, move up or down for a snake or a ladder
                square += board[square]
            }
        }
        print("Game over!")
        
        
        printEndLine(title)
    }
    
    /// 2.2 Repeat-While
    func repeatWhile() {
       
        let title = "2.2 Repeat-While";
        printStartLine(title)
        
        // 1）棋格数值初始化 棋盘使用 26 个零 Int 值初始化，而不是 25 个（从 0  到 25 ）
        let finalSquare = 25
        var board = [Int](repeating: 0, count: finalSquare + 1)
        
        // 2）根据方格内容，设置不同的值
        board[03] = +08 // 梯子，前进 8
        board[06] = +11 // 梯子，前进 11
        board[09] = +09 // 梯子，前进 9
        board[10] = +02 // 梯子，前进 2
        board[14] = -10 // 蛇，退 10
        board[19] = -11 // 蛇，退 11
        board[22] = -02 // 蛇，退 2
        board[24] = -08 // 蛇，退 8
        
        /* 使用 Repeat-While 改写上述蛇与梯子 */
        var square = 0
        var diceRoll = 0
        
        repeat {
            // move up or down for a snake or ladder
            square += board[square]
            // roll the dice
            diceRoll += 1
            if diceRoll == 7 {
                diceRoll = 1
            }
            // move by the rolled amount
            square += diceRoll
        } while square < finalSquare
        print("Game over!")
        
        printEndLine(title)
    }
    
    /// 3.1 If
    func usingIf() {
       
        let title = "3.1 If";
        printStartLine(title)
        
        // 只有 if
        var temperatureInFahrenheit = 30
        if temperatureInFahrenheit <= 32 {
            print("It's very cold. Consider wearing a scarf.") // scarf 围巾 😎
        }

        // 带有 else
        temperatureInFahrenheit = 40
        if temperatureInFahrenheit <= 32 {
            print("It's very cold. Consider wearing a scarf.")
        } else {
            print("It's not that cold. Wear a t-shirt.")
        }

        // 带有 else if
        temperatureInFahrenheit = 90
        if temperatureInFahrenheit <= 32 {
            print("It's very cold. Consider wearing a scarf.")
        } else if temperatureInFahrenheit >= 86 {
            print("It's really warm. Don't forget to wear sunscreen.")
        } else {
            print("It's not that cold. Wear a t-shirt.")
        }
        
        printEndLine(title)
    }
    
    /// 3.2.0 Switch
    func usingSwitch() {
       
        let title = "3.2.0 Switch";
        printStartLine(title)
        
        let someCharacter: Character = "z"
        switch someCharacter {
        case "a":
            print("The first letter of the alphabet")
        case "z":
            print("The last letter of the alphabet")
        default:
            print("Some other character")
        }
        
        printEndLine(title)
    }
    
    /// 3.2.1 没有隐式贯穿
    func noImplicitFallthrough() {
       
        let title = "3.2.1 没有隐式贯穿";
        printStartLine(title)
        
        /*
         1）switch 匹配到第一个情况执行完毕之后退出，不再需写 break
         2）每一个情况的函数体必须包含至少一个可执行的语句
         */
        let anotherCharacter: Character = "a"
        switch anotherCharacter {
//        case "a": // 此处❌
        case "A":
            print("The letter A")
        default:
            print("Not the letter A")
        }
        
        /* 匹配多个值可以用逗号分隔 */
        switch anotherCharacter {
        case "a", "A":
            print("The letter A")
        default:
            print("Not the letter A")
        }
        
        printEndLine(title)
    }
    
    /// 3.2.2 区间匹配
    func intervalMatching() {
       
        let title = "3.2.2 区间匹配";
        printStartLine(title)
        
        let approximateCount = 62
        let countedThings = "moons orbiting Saturn" // 卫星围绕土星旋转
        var naturalCount: String
        switch approximateCount {
        case 0:
            naturalCount = "no"
        case 1..<5:
            naturalCount = "a few"
        case 5..<12:
            naturalCount = "several"
        case 12..<100:
            naturalCount = "dozens of"
        case 100..<1000:
            naturalCount = "hundreds of"
        default:
            naturalCount = "many"
        }
        print("There are \(naturalCount) \(countedThings).")
        // 有几十颗卫星围绕土星旋转
        
        printEndLine(title)
    }
    
    /// 3.2.3 元组
    func tuples() {
       
        let title = "3.2.3 元组";
        printStartLine(title)
        
        /*
         使用元组来在一个 switch 语句中测试多个值。
         每个元组中的元素都可以与不同的值或者区间进行匹配。
         使用下划线 _ 来表明匹配所有可能的值。
         */
        
        let somePoint = (1, 1) // (0, 0) 只匹配第一个
        switch somePoint {
        case (0, 0):
            print("(0, 0) is at the origin")
        case (_, 0):
            print("(\(somePoint.0), 0) is on the x-axis")
        case (0, _):
            print("(0, \(somePoint.1)) is on the y-axis")
        case (-2...2, -2...2):
            print("(\(somePoint.0), \(somePoint.1)) is inside the box")
        default:
            print("(\(somePoint.0), \(somePoint.1)) is outside of the box")
        }
        // prints "(1, 1) is inside the box"
        
        
        printEndLine(title)
    }
    
    /// 3.2.4 值绑定
    func valueBindings() {
       
        let title = "3.2.4 值绑定";
        printStartLine(title)
        
        /* 将匹配到的值临时绑定为一个常量或者变量 */
        
        let anotherPoint = (2, 0)
        switch anotherPoint {
        case (let x, 0):
            print("on the x-axis with an x value of \(x)")
        case (0, let y):
            print("on the y-axis with a y value of \(y)")
        case let (x, y):
            print("somewhere else at (\(x), \(y))")
        }
        // prints "on the x-axis with an x value of 2"
        
        printEndLine(title)
    }
    
    /// 3.2.5 Where
    func usingWhere() {
       
        let title = "3.2.5 Where";
        printStartLine(title)
        
        /* 使用 where 分句来检查额外的情况 */
        let yetAnotherPoint = (1, -1)
        switch yetAnotherPoint {
        case let (x, y) where x == y:
            print("(\(x), \(y)) is on the line x == y")
        case let (x, y) where x == -y:
            print("(\(x), \(y)) is on the line x == -y")
        case let (x, y):
            print("(\(x), \(y)) is just some arbitrary point")
        }
        // prints "(1, -1) is on the line x == -y"
        
        printEndLine(title)
    }
    
    /// 3.2.6 复合情况
    func compoundCases() {
       
        let title = "3.2.6 复合情况";
        printStartLine(title)
        
        /* case 里面匹配多个情况 */
        let someCharacter: Character = "e"
        switch someCharacter {
        case "a", "e", "i", "o", "u":
            print("\(someCharacter) is a vowel")
        case "b", "c", "d", "f", "g", "h", "j", "k", "l", "m",
             "n", "p", "q", "r", "s", "t", "v", "w", "x", "y", "z":
            print("\(someCharacter) is a consonant")
        default:
            print("\(someCharacter) is not a vowel or a consonant")
        }
        // Prints "e is a vowel"
        
        /* 复合情况支持值绑定*/
        let stillAnotherPoint = (9, 0)
        switch stillAnotherPoint {
        case (let distance, 0), (0, let distance):
            print("On an axis, \(distance) from the origin")
        default:
            print("Not on an axis")
        }
        // Prints "On an axis, 9 from the origin"
        
        printEndLine(title)
    }
    
    /// 4.1 Continue
    func usingContinue() {
       
        let title = "4.1 Continue";
        printStartLine(title)
        
        let puzzleInput = "great minds think alike" // 英雄所见略同 😎
        var puzzleOutput = ""
        let charactersToRemove: [Character] = ["a", "e", "i", "o", "u", " "]
        for character in puzzleInput {
            if charactersToRemove.contains(character) {
                continue
            } else {
                puzzleOutput.append(character)
            }
        }
        print(puzzleOutput)
        // Prints "grtmndsthnklk"
        
        printEndLine(title)
    }
    
    /// 4.2.2 Switch 语句里的 Break
    func breakInASwitchStatement() {
       
        let title = "4.2.2 Switch 语句里的 Break";
        printStartLine(title)
        
        let numberSymbol: Character = "三"  // Simplified Chinese for the number 3
        var possibleIntegerValue: Int?
        switch numberSymbol {
        // 阿拉伯数字、奥利亚语、汉语、泰语 😎
        case "1", "١", "一", "๑":
            possibleIntegerValue = 1
        case "2", "٢", "二", "๒":
            possibleIntegerValue = 2
        case "3", "٣", "三", "๓":
            possibleIntegerValue = 3
        case "4", "٤", "四", "๔":
            possibleIntegerValue = 4
        default:
            break
        }
        if let integerValue = possibleIntegerValue {
            print("The integer value of \(numberSymbol) is \(integerValue).")
        } else {
            print("An integer value could not be found for \(numberSymbol).")
        }
        // prints "The integer value of 三 is 3."
        
        printEndLine(title)
    }
    
    /// 4.3 Fallthrough
    func usingFallthrough() {
       
        let title = "4.3 Fallthrough";
        printStartLine(title)
        
        /* 在 switch 里面延续 c 或者 oc 的贯穿行为 */
        let integerToDescribe = 5
        var description = "The number \(integerToDescribe) is"
        switch integerToDescribe {
        case 2, 3, 5, 7, 11, 13, 17, 19:
            description += " a prime number, and also"
            fallthrough
        default:
            description += " an integer."
        }
        print(description)
        // prints "The number 5 is a prime number, and also an integer."
        
        printEndLine(title)
    }
    
    /// 4.4 给语句打标签
    func labeledStatements() {
       
        let title = "4.4 给语句打标签";
        printStartLine(title)
        
        /*
         修改 2.1 While 玩蛇与梯子（也叫滑梯与梯子）游戏规则：
         - 要赢得游戏，必须精确地落在第25格上。
         - 如果特定的点数，超过了第25格，必须再次掷色子直到恰好得到了落到第25格的点数。
         */
        
        let finalSquare = 25
        var board = [Int](repeating: 0, count: finalSquare + 1)
        
        board[03] = +08
        board[06] = +11
        board[09] = +09
        board[10] = +02
        board[14] = -10
        board[19] = -11
        board[22] = -02
        board[24] = -08
        
        var square = 0
        var diceRoll = 0
        
    gameLoop: while square != finalSquare {
        diceRoll += 1
        if diceRoll == 7 { diceRoll = 1 }
        switch square + diceRoll {
        case finalSquare:
            // diceRoll will move us to the final square, so the game is over
            break gameLoop
        case let newSquare where newSquare > finalSquare:
            // diceRoll will move us beyond the final square, so roll again
            continue gameLoop
        default:
            // this is a valid move, so find out its effect
            square += diceRoll
            square += board[square]
        }
    }
        print("Game over!")
        
        printEndLine(title)
    }
    
    /// 5 提前退出
    func earlyExit() {
       
        let title = "5 提前退出";
        printStartLine(title)
        
        /*
         guard 语句，类似于 if 语句，基于布尔值表达式来执行语句。
         使用 guard 语句来要求一个条件必须是真才能执行 guard 之后的语句。
         与 if 语句不同， guard 语句总是有一个 else 分句—— else 分句里的代码会在条件不为真的时候执行
         */
        func greet(person: [String: String]) {
            guard let name = person["name"] else {
                return
            }
            
            print("Hello \(name)!")
            
            guard let location = person["location"] else {
                print("I hope the weather is nice near you.") // 我希望你附近的天气好。 😎
                return
            }
            
            print("I hope the weather is nice in \(location).")
        }
         
        greet(person: ["name": "John"])
        // Prints "Hello John!"
        // Prints "I hope the weather is nice near you."
        greet(person: ["name": "Jane", "location": "Cupertino"])
        // Prints "Hello Jane!"
        // Prints "I hope the weather is nice in Cupertino."
        
        printEndLine(title)
    }
    
    /// 6 检查API的可用性
    func checkingAPIAvailability() {
       
        let title = "6 检查API的可用性";
        printStartLine(title)
        
        /* 格式：
         if #available(platform name version, ..., *) {
             statements to execute if the APIs are available
         } else {
             fallback statements to execute if the APIs are unavailable
         }
         例如：
         在 iOS 平台， if 函数体只在 iOS 10 及以上版本才会执行；
         对于 macOS 平台，在只有在 macOS 10.12 及以上版本才会运行。
         最后一个实际参数， * ，它需求并表明在其他所有平台， if 函数体执行你在目标里明确的最小部属。
         */
        
        if #available(iOS 10, macOS 10.12, *) {
            // Use iOS 10 APIs on iOS, and use macOS 10.12 APIs on macOS
            
            print("iOS 10 +, macOS 10.12 +")
            
        } else {
            
            print("iOS 10 -, macOS 10.12 -")
        }
        
        printEndLine(title)
    }
}
